//
//   levelblit.c
//
//   Copyright 2007, 2008 Lancer-X/ASCEAI
//
//   This file is part of Meritous.
//
//   Meritous is free software: you can redistribute it and/or modify
//   it under the terms of the GNU General Public License as published by
//   the Free Software Foundation, either version 3 of the License, or
//   (at your option) any later version.
//
//   Meritous is distributed in the hope that it will be useful,
//   but WITHOUT ANY WARRANTY; without even the implied warranty of
//   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//   GNU General Public License for more details.
//
//   You should have received a copy of the GNU General Public License
//   along with Meritous.  If not, see <http://www.gnu.org/licenses/>.
//

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <time.h>
#include <SDL.h>
#include <SDL_image.h>
#include <assert.h>

#include "global.h"
#include "gamemap.h"
#include "tiles.h"
#include "viz_hooks.h"

#define PLAYERW 16
#define PLAYERH 24

#define MERITOUS_VERSION "v 1.1"
int RECORDING = 0;
int PLAYBACK = 0;

int expired_ms = 0;
int frame_len = 33;
int WriteBitmaps = 0;
int WB_StartRange = 0;
int WB_EndRange = 1000000;
int training = 0;
int game_paused = 0;
int show_ending = 0;
int voluntary_exit = 0;
int enter_room_x = 0, enter_room_y = 0;

FILE *record_file;
char record_filename[256];

void DrawLevel(int off_x, int off_y);
void DrawPlayer(int x, int y, int pl_dir, int pl_frm);
void LoadLevel();

void DrawCircle(int x, int y, int r, unsigned char c);

void HandleEvents();

void text_init();
void draw_text(int x, int y, char *str, Uint8 tcol);
unsigned char font_data[128][8][8];

void draw_text_ex(int x, int y, char *str, Uint8 tcol, SDL_Surface *srf);

int key_held[10] = {0};
int game_running = 1;

int player_x;
int player_y;
int player_dying;
int release_range;
int release_x;
int release_y;
int release_str;

int shield_hp;
int shield_recover;
int player_gems;
int checkpoints_found;
int circuit_size;
int first_game;
int player_hp;
int player_lives = 5;
int player_lives_part = 0;

int player_room;
int player_dir;
int player_wlk;
int player_walk_speed;
int wlk_wait;
int scroll_home;
int enter_pressed;

int opening_door_x, opening_door_y, opening_door_i = 0, opening_door_n;

int explored = 0;
//#define DEBUG_STATS 1

int artifacts[12];
SDL_Surface *artifact_spr = NULL;

int player_shield;
int circuit_fillrate;
int circuit_recoverrate;

int scroll_x, scroll_y;

int map_enabled;

int prv_player_room;

int specialmessage;
int specialmessagetimer;

int timer_ps = 0;
int timer_v[10];

float RandomDir()
{
	return (float)(rand()%256)*M_PI*2.0/256.0;
}

void PlayerDefaultStats()
{
	int i;

	player_dying = 0;
	release_range = 100;
	shield_hp = 0;
	shield_recover = 0;
	player_gems = 0;
	checkpoints_found = 0;
	circuit_size = 1000;
	first_game = 1;
	player_hp = 3;

	explored = 0;

	voluntary_exit = 0;
	player_room = 0;
	player_dir = 0;
	player_wlk = 0;
	player_walk_speed = 5;
	player_lives = 5;
	player_lives_part = 0;
	wlk_wait = 8;
	scroll_home = 0;
	enter_pressed = 0;
	show_ending = 0;

	game_paused = 0;

	player_shield = 0;
	circuit_fillrate = 2;
	circuit_recoverrate = 3;

	prv_player_room = -1;

	specialmessage = 0;
	specialmessagetimer = 0;

	opening_door_i = 0;

	map_enabled = 0;

	for (i = 0; i < 12; i++) {
		artifacts[i] = 0;
	}

#ifdef DEBUG_STATS

	player_shield = 24;
	circuit_fillrate = 24;
	circuit_recoverrate = 24;

	for (i = 0; i < 12; i++) {
		artifacts[i] = 1;
	}

#endif
}


void ScrollTo(int x, int y);
#define K_UP 0
#define K_DN 1
#define K_LT 2
#define K_RT 3
#define K_SP 4

SDL_Surface *screen;

void SetGreyscalePalette();
void SetTonedPalette(float pct);
void SetTitlePalette(int curve_start, int curve_end);
void SetTitlePalette2(int t);
int TouchTile(int ix, int iy);
void DrawRect(int x, int y, int w, int h, unsigned char c);

void DrawCircleEx(int x, int y, int r, int r2, unsigned char c);

void ThinLine(SDL_Surface *scr, int x1, int y1, int x2, int y2, Uint8 col);

#define SCREEN_W 640
#define SCREEN_H 480

void VideoUpdate()
{
	static int bmp = 0;
	char bmp_name[256];

	SDL_UpdateRect(screen, 0, 0, 0, 0);
	if (WriteBitmaps) {
		if ((bmp >= WB_StartRange)&&(bmp < WB_EndRange)) {
			sprintf(bmp_name, "v/bmp%d.bmp", bmp);
			SDL_SaveBMP(screen, bmp_name);
		}
		bmp++;
	}
}

void EndCycle(int n)
{
	static int last_ticks;
	int tick_delta;
	tick_delta = SDL_GetTicks() - last_ticks;

	if (n == 0) n = frame_len;

	if (tick_delta < n) {
		SDL_Delay(n-tick_delta);
	}

	if (!game_paused) expired_ms += n;

	last_ticks = SDL_GetTicks();
}

void WritePlayerData()
{
}

int min(int x, int y)
{
	if (x<y) return x;
	return y;
}

void DummyEventPoll()
{
	SDL_Event e;
	SDL_PollEvent(&e);
}

int DungeonPlay(void);

Uint8 Uint8_Bound(int c)
{
	if (c<0) return 0;
	if (c>255) return 255;
	return c;
}

int dist(int x1, int y1, int x2, int y2)
{
	int dx, dy;
	dx = x2 - x1;
	dy = y2 - y1;

	return sqrt((dx*dx)+(dy*dy));
}

void ClearInput()
{
	key_held[K_SP] = 0;
	key_held[K_UP] = 0;
	key_held[K_DN] = 0;
	key_held[K_LT] = 0;
	key_held[K_RT] = 0;
}

int main(int argc, char **argv)
{
	int executable_running = 1;
	int i;
	int option = 0;
	int can_continue = 0;
	int maxoptions;

	int ticker_tick = 0;
	unsigned int stime = 0;

    graph_init();
	if (argc > 1) {
		for (i = 1; i < argc; i++) {
		}
	}

	if ((RECORDING) && (PLAYBACK)) {
		exit(1);
	}
	struct timeval t;
	gettimeofday(&t, NULL);
	srand(t.tv_usec);
	if (RECORDING) {
		record_file = fopen(record_filename, "wb");
		stime = time(NULL);

		fputc(stime & 0x000000FF, record_file);
		fputc((stime & 0x0000FF00) >> 8, record_file);
		fputc((stime & 0x00FF0000) >> 16, record_file);
		fputc((stime & 0xFF000000) >> 24, record_file);

		srand(stime);
	}
	if (PLAYBACK) {
		record_file = fopen(record_filename, "rb");
		stime = fgetc(record_file);
		stime |= fgetc(record_file) << 8;
		stime |= fgetc(record_file) << 16;
		stime |= fgetc(record_file) << 24;

		srand(stime);
	}


	screen = SDL_SetVideoMode(SCREEN_W, SCREEN_H, 8, SDL_SWSURFACE | (SDL_FULLSCREEN * 0));
	if (!screen) {
		fprintf(stderr, "Couldn't set video mode: %s\n",
				SDL_GetError());
		exit(1);
	}


	text_init();

	SetGreyscalePalette();

	while (executable_running) {
		ticker_tick = 0;

		can_continue = 0;

		maxoptions = 2 + can_continue;

		ClearInput();

		if (executable_running == 1) {
			if ((option == 0) && can_continue) {
				DungeonPlay();
			} else {
				if (option == (0 + can_continue)) {
					training = 0;
					DungeonPlay();
				} else {
					training = 1;
					DungeonPlay();
				}
			}
			// clean up
			ClearInput();

			game_running = 1;
		}
	}

	SDL_Quit();
	return 0;
}

void ProgressBarScreen(int part, float progress, char *message, float t_parts)
{
	memset(screen->pixels, 0, 640*480);

	DrawRect(200, 217, 240, 50, 80);
	DrawRect(202, 219, 236, 46, 20);
	draw_text(232, 228, message, 255);
	DrawRect(232, 244, 176, 12, 128);
	DrawRect(234, 246, 172, 8, 0);

	if ((int)(172.0 * progress / t_parts + (172.0 / t_parts * part)) > 0) {
		DrawRect(234, 246, (int)(172.0 * progress / t_parts + (172.0 / t_parts * part)), 8, 200);
	}
	VideoUpdate();
	DummyEventPoll();
}

void LoadingScreen(int part, float progress)
{
	float t_parts;

	t_parts = 3.0;

	ProgressBarScreen(part, progress, "Loading... please wait", t_parts);
	ClearInput();
}

void SavingScreen(int part, float progress)
{
	ProgressBarScreen(part, progress, "Saving... please wait", 4.0);
	ClearInput();
}

void Arc(SDL_Surface *s, int x, int y, int r, float dir)
{
	int bright;
	int i, c;
	float pdir, cdir, ndir;

	int l_x = x, l_y = y;
	int cx, cy, c1x, c1y, c2x, c2y;

	bright = rand()%128+63;
	i = 0;
	while (i < r) {
		i += rand()%5+25;
		pdir = dir + (float)(rand()%16)/16.0*2.0*(M_PI / 15.0);
		ndir = dir - (float)(rand()%16)/16.0*2.0*(M_PI / 15.0);
		cdir = dir + (float)(rand()%16)/16.0*2.0*(M_PI / 20.0) - (float)(rand()%16)/16.0*2.0*(M_PI / 20.0);

		bright += rand()%30;
		bright -= rand()%30;

		if (bright < 0) bright = 0;
		if (bright > 255) bright = 255;

		c1x = x + cos(pdir) * i;
		c1y = y + sin(pdir) * i;
		ThinLine(s, l_x, l_y, c1x, c1y, bright);
		c2x = x + cos(ndir) * i;
		c2y = y + sin(ndir) * i;
		ThinLine(s, l_x, l_y, c2x, c2y, bright);

		for (c = 0; c < 5; c++) {
			DrawRect(x + cos(dir - (M_PI / 10.0) + (float)(rand()%16)/16.0*2.0*(M_PI / 10.0)) * i, y + sin(dir - (M_PI / 10.0) +
						(float)(rand()%16)/16.0*2.0*(M_PI / 10.0)) * i, 1, 1, rand()%128+63);
		}

		i += rand()%5+25;
		cx = x + cos(cdir) * i;
		cy = y + sin(cdir) * i;
		ThinLine(s, c1x, c1y, cx, cy, bright);
		ThinLine(s, c2x, c2y, cx, cy, bright);
		l_x = cx;
		l_y = cy;
	}

}

int DungeonPlay()
{
	int ix,  iy;
	int off_x, off_y;
	int t = 0;
	int i, j;
	int lost_gems;
	int can_move;

	char buf[50];

	expired_ms = 0;
	LoadingScreen(0, 0.0);

	viz_init_hooks();
	generate_dungeon(90,90,2,4);

	PlayerDefaultStats();
	player_x = 1 + ((rooms[0].x + ceil(rooms[0].w/2)) * 32 - PLAYERW/2);
	player_y = 1 + ((rooms[0].y + ceil(rooms[0].h/2)) * 32 - PLAYERH/2);

	InitAutomap();

	game_running = 1;
	while (game_running) {
		//sprintf(buf, "X: %d  Y: %d", (player_x + PLAYERW/2)/32*32 + PLAYERW/2, (player_y + PLAYERH/2)/32*32 + PLAYERH/2);
		//SDL_WM_SetCaption(buf, "MT");
		if (!game_paused) {
			if (player_dying > 30) {
				player_hp--;

				if (player_hp <= 0) {
					if (!training) player_lives--;
					lost_gems = player_gems / 3;
					player_gems -= lost_gems;

					lost_gems = lost_gems * 95 / 100;

					player_dying = 0;
					shield_hp = 0;

					scroll_home = 1;
					player_hp = 3 + (player_shield == 30)*3;
				} else {
					player_dying = 0;
				}
			}
		}

		circuit_size = 250 + 50*(circuit_fillrate + circuit_recoverrate);

		player_room = viz_get_room(player_x/32, player_y/32);

		if (player_room != prv_player_room) {
			SetTonedPalette(0);
			prv_player_room = player_room;
			RecordRoom(player_room);

			enter_room_x = player_x;
			enter_room_y = player_y;

		}

		if (!map_enabled) {
			ScrollTo(player_x + PLAYERW/2 - 320, player_y + PLAYERH/2 - 240);
			DrawLevel(scroll_x, scroll_y);
			//DrawLevel(player_x + 8 - 320, player_y + 12 - 240);

			if (player_dying == 0) {

				DrawPlayer(312, 228, player_dir, player_wlk / wlk_wait);
			} else {
				if (t % 2 == 0) DrawPlayer(312, 228, player_dir, player_wlk / wlk_wait);

				if (!game_paused)
					player_dying++;
			}
			t++;

			if (opening_door_i > 0) {
				for (i = 0; i < 5; i++) {
					j = i * 50 - 250 + (opening_door_i * 5);
					if (j > 0) {
						DrawCircle(player_x - scroll_x, player_y - scroll_y, j, 255);
					}
				}

				if (!game_paused) {
					opening_door_i++;
					if (opening_door_i >= 100) {
						opening_door_i = 0;
					}
				}
			}

			if (!game_paused) {
				if (shield_hp < player_shield) {
					shield_recover += player_shield * 3 / (3 - training - (player_shield == 30));
					if (artifacts[1]) shield_recover += player_shield * 3 / (3 - training - (player_shield == 30));
					if (shield_recover >= 50) {
						shield_hp++;
						shield_recover -= 50 - (player_shield == 30)*25;
					}
				}
			}
		}

		if (map_enabled) DisplayAutomap();

		if (game_paused && (!map_enabled) && (!voluntary_exit)) {
			for (i = 0; i < 10; i++) {
				DrawRect((640 - 6 * 8) / 2 - i, (480 - 8) / 2 - i, 6*8 + 2*i, 8 + 2*i, 64 - i*5);
			}
			draw_text((640 - 6 * 8) / 2, (480 - 8) / 2, "Paused", 255);

				{
				int t_days;
				int t_hours;
				int t_minutes;
				int t_seconds;

				t_seconds = (expired_ms / 1000) % 60;
				t_minutes = ((expired_ms / 1000) / 60) % 60;
				t_hours = (((expired_ms / 1000) / 60) / 60) % 24;
				t_days = (((expired_ms / 1000) / 60) / 60) / 24;

				if (t_days > 0) {
					sprintf(buf, "%dd %dh %dm %ds", t_days, t_hours, t_minutes, t_seconds);
				} else {
					if (t_hours > 0) {
						sprintf(buf, "%dh %dm %ds", t_hours, t_minutes, t_seconds);
					} else {
						sprintf(buf, "%dm %ds", t_minutes, t_seconds);
					}
				}
				draw_text(636 - strlen(buf)*8, 470, buf, 255);
				}
		}

		if (voluntary_exit) {
			exit(0);
		}

		VideoUpdate();

		EndCycle(0);

		can_move = 1;

		if ((player_dying != 0) && (player_hp <= 1)) can_move = 0;

		if (scroll_home != 0) can_move = 0;
		if (opening_door_i != 0) can_move = 0;
		if (game_paused) can_move = 0;

		HandleEvents();
		if (map_enabled) {
			game_paused = 1;
		}

		if (can_move) {

			ix = player_x;
			iy = player_y;
			off_x = 0;
			off_y = 0;
			if (key_held[K_UP] && !key_held[K_DN]) {
				iy -= player_walk_speed * (artifacts[4]?1.4:1);
				player_dir = 0;
			}
			if (key_held[K_DN] && !key_held[K_UP]) {
				iy += player_walk_speed * (artifacts[4]?1.4:1);;
				player_dir = 1;
				off_y = 24;
			}
			if (key_held[K_LT] && !key_held[K_RT]) {
				ix -= player_walk_speed * (artifacts[4]?1.4:1);;
				if (!(key_held[K_UP] || key_held[K_DN])) {
					player_dir = 3;
				}
			}
			if (key_held[K_RT] && !key_held[K_LT]) {
				off_x = 16;
				ix += player_walk_speed * (artifacts[4]?1.4:1);;
				if (!(key_held[K_UP] || key_held[K_DN])) {
					player_dir = 2;

				}
			}
			if ((key_held[K_SP])) {
			}

			if ((ix!=player_x)||(iy!=player_y)) {
				// Are we changing to a new square?
				if (((player_x / 32)!=((ix+off_x) / 32)) || ((player_y / 32)!=((iy+off_y) / 32))) {
					//printf("%d\n", tile);
					if (TouchTile(ix, iy)) {
						player_wlk = (player_wlk + 1 + artifacts[4]*3) % (4*wlk_wait);
					} else {
						if (TouchTile(player_x, iy)) {
							player_wlk = (player_wlk + 1 + artifacts[4]*3) % (4*wlk_wait);
						} else {
							if (TouchTile(ix, player_y)) {
								player_wlk = (player_wlk + 1 + artifacts[4]*3) % (4*wlk_wait);
								if (off_x > 0) player_dir = 2;
								else player_dir = 3;
							}
						}

					}
				} else {
					player_x = ix;
					player_y = iy;

					player_wlk = (player_wlk + 1 + artifacts[4]*3) % (4*wlk_wait);
				}
			}
		}

		if (voluntary_exit && enter_pressed) {
			voluntary_exit = 0;
			game_running = 0;
			game_paused = 0;
		}

		if ((player_lives == 0) && (!training)) {
			break;
		}
		if (show_ending) {
			break;
		}
	}

	if ((player_lives == 0) && (!training)) {
		SDL_FillRect(screen, NULL, 0);
		draw_text(252, 236, "G A M E   O V E R", 255);
		VideoUpdate();
		SDL_Delay(2000);
	}

	return 0;
}

void CancelVoluntaryExit()
{
	if (voluntary_exit) {
		voluntary_exit = 0;
		game_paused = 0;
	}
}

void HandleEvents()
{
	unsigned short db;
	static SDL_Event event;
	int pressed_tab = 0;

	if (PLAYBACK) {
		db = fgetc(record_file);
		db |= fgetc(record_file) << 8;

		key_held[K_UP] = (db & 0x0001)>0;
		key_held[K_DN] = (db & 0x0002)>0;
		key_held[K_LT] = (db & 0x0004)>0;
		key_held[K_RT] = (db & 0x0008)>0;
		key_held[K_SP] = (db & 0x0010)>0;
		enter_pressed  = (db & 0x0020)>0;
		map_enabled    = (db & 0x0040)>0;
		game_running   = (db & 0x0080)>0;
		game_paused    = (db & 0x0100)>0;
		voluntary_exit = (db & 0x0200)>0;
		pressed_tab    = (db & 0x0400)>0;

		return;
	}

	if (pressed_tab) {
		c_scroll_x = player_x;
		c_scroll_y = player_y;
	}

	enter_pressed = 0;
	while (SDL_PollEvent(&event)) {
		if (event.type == SDL_KEYDOWN) {
			switch (event.key.keysym.sym) {
				case SDLK_w:
				case SDLK_UP:
					key_held[K_UP] = 1;
					CancelVoluntaryExit();
					break;
				case SDLK_s:
				case SDLK_DOWN:
					key_held[K_DN] = 1;
					CancelVoluntaryExit();
					break;
				case SDLK_a:
				case SDLK_LEFT:
					key_held[K_LT] = 1;
					CancelVoluntaryExit();
					break;
				case SDLK_d:
				case SDLK_RIGHT:
					key_held[K_RT] = 1;
					CancelVoluntaryExit();
					break;
				case SDLK_SPACE:
					key_held[K_SP] = 1;
					CancelVoluntaryExit();
					break;
				case SDLK_RETURN:
					enter_pressed = 1;
					break;
				case SDLK_ESCAPE:
					if (map_enabled) {
						map_enabled = 0;
						game_paused = 0;
					} else {
						voluntary_exit ^= 1;
						game_paused = voluntary_exit;
					}
					break;
				case SDLK_TAB:
					pressed_tab = 1;
					map_enabled ^= 1;
					game_paused = map_enabled;
					c_scroll_x = player_x;
					c_scroll_y = player_y;
					CancelVoluntaryExit();
					break;
				case SDLK_p:
					game_paused ^= 1;
					CancelVoluntaryExit();
					break;


					/*
					   case SDLK_j:
					   {
					   player_shield = 20;
					   circuit_recoverrate = 20;
					   circuit_fillrate = 20;
					   }
					   break;
					   case SDLK_k:
					   {
					   int i, n, j;
					   for (j = 0; j < 1; j++) {
					   for (i = 0; i < 50000; i++) {
					   n = rand()%3000;
					   if (rooms[n].visited == 0) {
					   player_x = rooms[n].x * 32 + rooms[n].w * 16;
					   player_y = rooms[n].y * 32 + rooms[n].h * 16;
					   rooms[n].visited = 1;
					   explored++;
					   break;
					   }
					   }
					   }
					   }
					   break;

					   case SDLK_m:
					   {
					   int i;
					   for (i = 0; i < 8; i++) {
					   artifacts[i] = 1;
					   }
					   for (i = 8; i < 11; i++) {
					   artifacts[i] = 0;
					   }
					   artifacts[11] = 0;
					   }
					   break;

					   case SDLK_n:
					   {
					   expired_ms = 1000000;
					   }
					   break;
					   */
				default:
					break;
			}
		}
		if (event.type == SDL_KEYUP) {
			switch (event.key.keysym.sym) {
				case SDLK_w:
				case SDLK_UP:
					key_held[K_UP] = 0;
					break;
				case SDLK_s:
				case SDLK_DOWN:
					key_held[K_DN] = 0;
					break;
				case SDLK_a:
				case SDLK_LEFT:
					key_held[K_LT] = 0;
					break;
				case SDLK_d:
				case SDLK_RIGHT:
					key_held[K_RT] = 0;
					break;
				case SDLK_SPACE:
					key_held[K_SP] = 0;
					break;
				default:
					break;
			}
		}
		if (event.type == SDL_QUIT) {
			voluntary_exit = 1;
		}
	}

	if (RECORDING) {
		db = 0;

		db |= 0x0001 * key_held[K_UP];
		db |= 0x0002 * key_held[K_DN];
		db |= 0x0004 * key_held[K_LT];
		db |= 0x0008 * key_held[K_RT];
		db |= 0x0010 * key_held[K_SP];
		db |= 0x0020 * enter_pressed;
		db |= 0x0040 * map_enabled;
		db |= 0x0080 * game_running;
		db |= 0x0100 * game_paused;
		db |= 0x0200 * voluntary_exit;
		db |= 0x0400 * pressed_tab;

		fputc(db & 0x00FF, record_file);
		fputc((db & 0xFF00)>>8, record_file);
		return;
	}

}

void DrawLevel(int off_x, int off_y)
{
	static SDL_Surface *tiles = NULL;
	static SDL_Surface *fog = NULL;
	Uint8 *pp;
	SDL_Rect tilerec, screenrec;
	int x, y, i;
	int resolve_x, resolve_y;

	DrawRect(0, 0, 640, 480, 255);

	if (tiles == NULL) {
		tiles = IMG_Load("meritous/dat/i/tileset.png");
		fog = IMG_Load("meritous/dat/i/tileset.png");

		pp = fog->pixels;

		for (i = 0; i < fog->w*fog->h; i++) {
			*pp = *pp / 2 + 128;
			pp++;
		}
	}
	for (y = 0; y < 16; y++) {
		for (x = 0; x < 21; x++) {
			resolve_x = x + (off_x/32);
			resolve_y = y + (off_y/32);

			tilerec.x = viz_get_tile(resolve_x, resolve_y) * 32;
			tilerec.y = 0;
			tilerec.w = 32;
			tilerec.h = 32;

			screenrec.x = x*32 - ( (off_x) %32);
			screenrec.y = y*32 - ( (off_y) %32);
			screenrec.w = 0;
			screenrec.h = 0;


			SDL_BlitSurface(tiles, &tilerec, screen, &screenrec);
		}
	}

	for (i = 0; i < 3000; i++) {
		char str[10];
		sprintf(str, "%d", i);
		if (rooms[i].x == 0 && rooms[i].y == 0 && rooms[i].w == 0)
			break;
		x = - off_x + rooms[i].x*32 + rooms[i].w*32 / 2;
		y = - off_y + rooms[i].y*32 + rooms[i].h*32 / 2;
		if (!(x < 0 || x > screen->w || y < 0 || y > screen->h-8)) {
			draw_text_ex(x,y, str, 255, screen);
			if (viz_has_gift(i) && x-5 > 0 && y+10 < screen->h-8)
				draw_text_ex(x-5, y+10, "GIFT", 255, screen);
		}

		x = - off_x + rooms[i].x*32 + rooms[i].w*32 / 2;
		y = - off_y + rooms[i].y*32 + rooms[i].h*32 - 15;
		sprintf(str,"E: %d", rooms[i].enemy_diff);
		if (!(x < 0 || x > screen->w - 10|| y < 0 || y > screen->h - 10)) {
			draw_text_ex(x,y, str, 120, screen);
		}

	}


}

void DrawPlayer(int x, int y, int pl_dir, int pl_frm)
{
	static SDL_Surface *playersprite = NULL;
	SDL_Rect playerrec, screenrec;

	if (playersprite == NULL) {
		playersprite = IMG_Load("meritous/dat/i/player.png");
		SDL_SetColorKey(playersprite, SDL_SRCCOLORKEY | SDL_RLEACCEL, 0);
	}

	playerrec.x = pl_frm * 16;
	playerrec.y = pl_dir * 24;
	playerrec.w = 16;
	playerrec.h = 24;

	screenrec.x = x;
	screenrec.y = y;

	SDL_BlitSurface(playersprite, &playerrec, screen, &screenrec);
}

void SetGreyscalePalette()
{
	SDL_Color grey[256];
	SDL_Color pal[256];
	int i;

	float ip;

	for (i = 0; i < 256; i++) {
		grey[i].r = grey[i].g = grey[i].b = i;
	}

	for (i = 0; i < 256; i++) {
		ip = (float)i / 255.0;
		pal[i].r = (cos(ip * M_PI / 2.0 + M_PI) + 1.0) * 255;
		pal[i].g = (sin(ip * M_PI / 2.0) * 255 + i) / 2;
		pal[i].b = sin(ip * M_PI / 2.0) * 255;
	}

	SDL_SetPalette(screen, SDL_LOGPAL, grey, 0, 256);
	SDL_SetPalette(screen, SDL_PHYSPAL, pal, 0, 256);
}

void SetTonedPalette(float dct)
{
	SDL_Color pal[256];
	float pct = 1.0 - dct;
	float rp_dct, rp_pct;
	float ip;
	int ec;
	int i;
	static int tk = 0;

	ec = 0;

	rp_dct = (float)ec / 50.0;
	rp_pct = 1.0 - rp_dct;

	if (artifacts[11]) {
		if (player_room == 0) {
			tk++;
			pct = sin((float)tk / 33.0 * M_PI) * 0.5 + 0.5;
			for (i = 0; i < 256; i++) {
				pal[i].r = i;
				pal[i].g = (i / 3)*pct;
				pal[i].b = (i * 2 / 3)*pct;
			}
		} else {
			for (i = 0; i < 256; i++) {
				ip = (float)i / 255.0;
				pal[i].r = i;
				pal[i].g = i * dct;
				pal[i].b = (cos(ip * M_PI / 2.0 + M_PI) + 1.0) * 255 * dct;
			}
		}

	} else {
		for (i = 0; i < 256; i++) {
			ip = (float)i / 255.0;
			pal[i].r = (((cos(ip * M_PI / 2.0 + M_PI) + 1.0) * 255)*pct + i*dct)*rp_pct + (sin(ip * M_PI / 2.0) * 207 + 48)*rp_dct;
			pal[i].g = (i)*rp_pct + ((cos(ip * M_PI / 2.0 + M_PI) + 1.0) * 255)*rp_dct;
			pal[i].b = ((sin(ip * M_PI / 2.0) * 255 * pct)+((cos(ip * M_PI / 2.0 + M_PI) + 1.0) * 255 * dct))*rp_pct + ((cos(ip * M_PI / 2.0 + M_PI) + 1.0) * 255)*rp_dct;
		}
	}

	SDL_SetPalette(screen, SDL_PHYSPAL, pal, 0, 256);
}

void SetTitlePalette(int curve_start, int curve_end)
{
	SDL_Color pal[256];
	int ec;
	int i;

	for (i = 0; i < 256; i++) {
		ec = (i - curve_start) * 255 / (curve_end-curve_start);
		if (ec < 0) ec = 0;
		if (ec > 255) ec = 255;

		pal[i].r = ec;
		pal[i].g = ec;
		pal[i].b = ec;
	}

	SDL_SetPalette(screen, SDL_PHYSPAL, pal, 0, 256);
}

void SetTitlePalette2(int t)
{
	SDL_Color pal[256];
	int i;

	float ip;
	float bright;
	float b_coeff;

	bright = 1 - ((float)t / 30.0);
	if (bright < 0.0) bright = 0.0;
	b_coeff = 1 - bright;

	for (i = 0; i < 256; i++) {
		ip = (float)i / 255.0;
		pal[i].r = (cos(ip * M_PI / 2.0 + M_PI) + 1.0) * 255 * b_coeff + 255*bright;
		pal[i].g = (sin(ip * M_PI / 2.0) * 255 + i) / 2 * b_coeff + 255*bright;
		pal[i].b = sin(ip * M_PI / 2.0) * 255 * b_coeff + 255*bright;
	}

	SDL_SetPalette(screen, SDL_PHYSPAL, pal, 0, 256);
}

int IsSolid(unsigned char tile)
{
	return TileData[tile].Is_Solid;
}

int TouchTile(int ix, int iy)
{
	int i;
	int off_x, off_y;
	int ret = 1;
	unsigned char tile;

	for (i = 0; i < 4; i++) {
		off_x = 15*(i%2);
		off_y = 23*(i/2);

		tile = viz_get_tile((ix+off_x)/32, (iy+off_y)/32);
		switch (tile) {
			case 13:
				player_x = (ix + off_x) / 32 * 32 + 8;
				player_y = (iy/32 + 2)*32 + 32;
				return 1;
				break;
			case 14:
				player_x = (ix + off_x) / 32 * 32 + 8;
				player_y = (iy/32 - 2)*32 + 8;
				return 1;
				break;
			case 15:
				player_x = (ix/32 + 2)*32 + 32;
				player_y = (iy + off_y) / 32 * 32 + 4;
				return 1;
				break;
			case 16:
				player_x = (ix/32 - 2)*32 + 16;
				player_y = (iy + off_y) / 32 * 32 + 4;
				return 1;
				break;
			default:
				if (TileData[tile].Is_Solid) ret = 0;
				//ret = 0;
				break;
		}
	}
	if (ret == 1) {
		player_x = ix;
		player_y = iy;
	}
	return ret;
}

void text_init()
{
	FILE *font_data_file;
	int chr, x, y;
	font_data_file = fopen("meritous/dat/d/font.dat", "rb");

	for (chr = 0; chr < 128; chr++) {
		for (y = 0; y < 8; y++) {
			for (x = 0; x < 8; x++) {
				font_data[chr][x][y] = fgetc(font_data_file);
			}
		}
	}

	fclose(font_data_file);
}

void draw_char(int cur_x, int cur_y, int c, Uint8 tcol)
{
	int px, py;
	Uint8 *pix;

	for (py = 0; py < 8; py++) {
		pix = (Uint8 *)screen->pixels;
		pix += (py+cur_y)*screen->w;
		pix += cur_x;

		if ((cur_x >= 0)&&(py+cur_y >= 0)&&(cur_x < screen->w-8)&&(py+cur_y < screen->h)) {
			for (px = 0; px < 8; px++) {
				if (font_data[c][px][py] == 255) {
					*pix = tcol;
				}
				if ((font_data[c][px][py] < 255)&&(font_data[c][px][py] > 0)) {
					*pix = ((int)tcol * font_data[c][px][py] / 256) + ((int)*pix * (256-font_data[c][px][py]) / 256);
				}
				pix++;
			}
		}
	}
}

void draw_text(int x, int y, char *str, Uint8 tcol)
{
	int c, cur_x, cur_y;

	cur_x = x;
	cur_y = y;

	while (*str != 0) {
		c = *(str++);
		if (c == '\n') {
			cur_x = x;
			cur_y+=10;
		} else {
			draw_char(cur_x, cur_y, c, tcol);
			cur_x+=8;
		}
	}
}

void draw_text_ex(int x, int y, char *str, Uint8 tcol, SDL_Surface *srf)
{
	Uint8 *pix;
	int c, cur_x, cur_y, px, py;

	cur_x = x;
	cur_y = y;

	while (*str != 0) {
		c = *(str++);
		if (c == '\n') {
			cur_x = x;
			cur_y+=8;
		} else {
			for (py = 0; py < 8; py++) {
				pix = (Uint8 *)srf->pixels;
				pix += (py+cur_y)*srf->w;
				pix += cur_x;
				for (px = 0; px < 8; px++) {
					if (font_data[c][px][py]) {
						*pix = tcol;
					}
					pix++;
				}
			}
			cur_x+=8;
		}
	}
}

void DrawRect(int x, int y, int w, int h, unsigned char c)
{
	SDL_Rect r;

	r.x = x;
	r.y = y;
	r.w = w;
	r.h = h;

	SDL_FillRect(screen, &r, c);
}

void DrawCircle(int x, int y, int r, unsigned char c)
{
	int circ_y;

	int len_x, outer_len_x, inner_len_x;

	int inner_r = r - 10;
	if (inner_r < 1) inner_r = 1;

	if (r < 1) return;
	// a^2 + b^2 = c^2
	for (circ_y = 0; circ_y < r; circ_y++) {
		if (circ_y < (r-10)) {
			outer_len_x = sqrt(r*r - circ_y*circ_y);
			inner_len_x = sqrt((r-10)*(r-10) - circ_y*circ_y);
			DrawRect(x - outer_len_x, y - circ_y, (outer_len_x - inner_len_x), 1, c);
			DrawRect(x + inner_len_x, y - circ_y, (outer_len_x - inner_len_x), 1, c);
			DrawRect(x - outer_len_x, y + circ_y, (outer_len_x - inner_len_x), 1, c);
			DrawRect(x + inner_len_x, y + circ_y, (outer_len_x - inner_len_x), 1, c);
		} else {
			len_x = sqrt(r*r - circ_y*circ_y);

			DrawRect(x - len_x, y - circ_y, len_x*2, 1, c);
			DrawRect(x - len_x, y + circ_y, len_x*2, 1, c);
		}
	}
}

void DrawCircleEx(int x, int y, int r, int r2, unsigned char c)
{
	int circ_y;

	int len_x, outer_len_x, inner_len_x;

	int inner_r = r2;
	int diffi = r-r2;
	if (inner_r < 1) inner_r = 1;



	if (r < 1) return;
	// a^2 + b^2 = c^2
	for (circ_y = 0; circ_y < r; circ_y++) {
		if (circ_y < (r-diffi)) {
			outer_len_x = sqrt(r*r - circ_y*circ_y);
			inner_len_x = sqrt((r-diffi)*(r-diffi) - circ_y*circ_y);
			DrawRect(x - outer_len_x, y - circ_y, (outer_len_x - inner_len_x), 1, c);
			DrawRect(x + inner_len_x, y - circ_y, (outer_len_x - inner_len_x), 1, c);
			DrawRect(x - outer_len_x, y + circ_y, (outer_len_x - inner_len_x), 1, c);
			DrawRect(x + inner_len_x, y + circ_y, (outer_len_x - inner_len_x), 1, c);
		} else {
			len_x = sqrt(r*r - circ_y*circ_y);

			DrawRect(x - len_x, y - circ_y, len_x*2, 1, c);
			DrawRect(x - len_x, y + circ_y, len_x*2, 1, c);
		}
	}
}

void TeleportPlayerToRoom(int c_room)
{
	player_x = rooms[c_room].x * 32 + (rooms[c_room].w / 2 * 32) + 8;
	player_y = rooms[c_room].y * 32 + (rooms[c_room].h / 2 * 32) + 4;
	c_scroll_x = player_x;
	c_scroll_y = player_y;
	scroll_home = 1;
}


void TeleportPlayerToNextRoom()
{
	int c_room;
	c_room = (player_room + 1) % 3000;

	if (c_room == 0) {
		player_x = 8232;
		player_y = 8108;
	} else {
		player_x = rooms[c_room].x * 32 + (rooms[c_room].w / 2 * 32) + 8;
		player_y = rooms[c_room].y * 32 + (rooms[c_room].h / 2 * 32) + 4;
	}
	c_scroll_x = player_x;
	c_scroll_y = player_y;
	scroll_home = 1;
}

void ScrollTo(int x, int y)
{
	static int scrollspeed_x = 1, scrollspeed_y = 1;
	if (scroll_home == 0) {
		scroll_x = x;
		scroll_y = y;
		return;
	}

	if (scroll_home == 1) {
		scrollspeed_x = (x - scroll_x)/20;
		scrollspeed_y = (y - scroll_y)/20;
		scroll_home = 2;
	}

	if (scroll_home == 2) {
		scroll_x += (x - scroll_x)/2;
		scroll_y += (y - scroll_y)/2;

		if ((abs(scroll_x-x)<2)&&(abs(scroll_y-y)<2)) {
			scroll_x = x;
			scroll_y = y;
			scroll_home = 0;
		}
	}
}


void Swap(int *a, int *b)
{
	*a ^= *b ^= *a ^= *b;
}

void ThinLine(SDL_Surface *scr, int x1, int y1, int x2, int y2, Uint8 col)
{
	int dx, dy, dm;
	int i, j;

	(void) scr;
	dx = (x2 - x1);
	dy = (y2 - y1);

	dm = abs(dx) > abs(dy) ? dx : dy;

	if (dm == 0) return;

	if (dm < 0) {
		Swap(&x1, &x2);
		Swap(&y1, &y2);
		dx = (x2 - x1);
		dy = (y2 - y1);

		dm = dm * -1;
	}

	if (dm == dx) {
		if (dy == 0) {
			DrawRect(x1, y1, x2-x1+1, 1, col);
			return;
		}
		for (i = 0; i < dm; i++) {
			j = (dy * i / dm);
			DrawRect(i+x1, j+y1, 1, 1, col);
		}
	}
	if (dm == dy) {
		if (dx == 0) {
			DrawRect(x1, y1, 1, y2-y1+1, col);
			return;
		}
		for (i = 0; i < dm; i++) {
			j = (dx * i / dm);
			DrawRect(j+x1, i+y1, 1, 1, col);
		}
	}
}
